package redis_core

import (
	"context"
	"github.com/fsnotify/fsnotify"
	"github.com/redis/go-redis/v9"
	"go_server/game_server/util"
	"go_server/zinx/zconstant"
	"go_server/zinx/zlog"
)

var (
	game_redis      *redis.Client
	center_redis    *redis.Client
	login_redis     *redis.Client
	subscribe_redis *redis.Client
	//game_redis_once sync.Once
)

type redisConfig struct {
	GameRedis      zconstant.RedisClient `mapstructure:"game";json:"gameRedis"`
	CenterRedis    zconstant.RedisClient `mapstructure:"center";json:"centerRedis"`
	LoginRedis     zconstant.RedisClient `mapstructure:"login";json:"loginRedis"`
	SubscribeRedis zconstant.RedisClient `mapstructure:"subscribe";json:"subscribeRedis"`
}

var redisClient *redisConfig

func GetGameRedisClient() *redis.Client {
	return game_redis
}

func GetSubscribeRedisClient() *redis.Client {
	return subscribe_redis
}

func createRedisClient(addr string, pass string, db int, name string, minIdleConns int,
	maxIdleConns int, poolSize int) *redis.Client {
	cli := redis.NewClient(&redis.Options{
		Addr:       addr,
		Password:   pass,
		DB:         db,
		ClientName: name,
		MinIdleConns: minIdleConns,
		MaxIdleConns: maxIdleConns,
		PoolSize: poolSize,
	})

	if err := cli.Ping(context.Background()).Err(); err != nil {
		zlog.Panicf("connect to %s redis %d failed %v", name, db, err)
	} else {
		zlog.Infof("connect to %s redis %d success!!!\n\n", name, db)
	}
	return cli
}

func Init() {
	viper, _ := util.CreateConfig("redis")
	viper.WatchConfig()
	if err := viper.Unmarshal(&redisClient); err != nil {
		zlog.Panicf("unable to decode into struct, %v", err)
	}

	game_redis = createRedisClient(redisClient.GameRedis.Addr, redisClient.GameRedis.Password,
		redisClient.GameRedis.SelectDb, "GAME", redisClient.GameRedis.MinIdleConns,
		redisClient.GameRedis.MaxIdleConns, redisClient.GameRedis.PoolSize)

	center_redis = createRedisClient(redisClient.CenterRedis.Addr, redisClient.CenterRedis.Password,
		redisClient.CenterRedis.SelectDb, "CENTER", redisClient.CenterRedis.MinIdleConns,
		redisClient.CenterRedis.MaxIdleConns, redisClient.CenterRedis.PoolSize)

	login_redis = createRedisClient(redisClient.LoginRedis.Addr, redisClient.LoginRedis.Password,
		redisClient.LoginRedis.SelectDb, "LOGIN", redisClient.LoginRedis.MinIdleConns,
		redisClient.LoginRedis.MaxIdleConns, redisClient.LoginRedis.PoolSize)

	subscribe_redis = createRedisClient(redisClient.SubscribeRedis.Addr, redisClient.SubscribeRedis.Password,
		redisClient.SubscribeRedis.SelectDb, "SUBSCRIBE", redisClient.SubscribeRedis.MinIdleConns,
		redisClient.SubscribeRedis.MaxIdleConns, redisClient.SubscribeRedis.PoolSize)
	
	viper.OnConfigChange(func(in fsnotify.Event) {
		changeMinIdle := viper.GetInt("game.min_idle_conns")
		if changeMinIdle != redisClient.GameRedis.MinIdleConns {
			game_redis.Options().MinIdleConns = changeMinIdle
			redisClient.GameRedis.MinIdleConns = changeMinIdle
		}

		changeMaxIdle := viper.GetInt("game.max_idle_conns")
		if changeMaxIdle != redisClient.GameRedis.MaxIdleConns {
			game_redis.Options().MaxIdleConns = changeMaxIdle
			redisClient.GameRedis.MaxIdleConns = changeMaxIdle
		}

		changePoolSize := viper.GetInt("game.pool_size")
		if changePoolSize != redisClient.GameRedis.PoolSize {
			game_redis.Options().PoolSize = changePoolSize
			redisClient.GameRedis.PoolSize = changePoolSize
		}



		changeMinIdle = viper.GetInt("center.min_idle_conns")
		if changeMinIdle != redisClient.CenterRedis.MinIdleConns {
			center_redis.Options().MinIdleConns = changeMinIdle
			redisClient.CenterRedis.MinIdleConns = changeMinIdle
		}

		changeMaxIdle = viper.GetInt("center.max_idle_conns")
		if changeMaxIdle != redisClient.CenterRedis.MaxIdleConns {
			center_redis.Options().MaxIdleConns = changeMaxIdle
			redisClient.CenterRedis.MaxIdleConns = changeMaxIdle
		}

		changePoolSize = viper.GetInt("center.pool_size")
		if changePoolSize != redisClient.CenterRedis.PoolSize {
			center_redis.Options().PoolSize = changePoolSize
			redisClient.CenterRedis.PoolSize = changePoolSize
		}



		changeMinIdle = viper.GetInt("login.min_idle_conns")
		if changeMinIdle != redisClient.LoginRedis.MinIdleConns {
			login_redis.Options().MinIdleConns = changeMinIdle
			redisClient.LoginRedis.MinIdleConns = changeMinIdle
		}

		changeMaxIdle = viper.GetInt("login.max_idle_conns")
		if changeMaxIdle != redisClient.LoginRedis.MaxIdleConns {
			login_redis.Options().MaxIdleConns = changeMaxIdle
			redisClient.LoginRedis.MaxIdleConns = changeMaxIdle
		}

		changePoolSize = viper.GetInt("login.pool_size")
		if changePoolSize != redisClient.LoginRedis.PoolSize {
			login_redis.Options().PoolSize = changePoolSize
			redisClient.LoginRedis.PoolSize = changePoolSize
		}



		changeMinIdle = viper.GetInt("subscribe.min_idle_conns")
		if changeMinIdle != redisClient.SubscribeRedis.MinIdleConns {
			subscribe_redis.Options().MinIdleConns = changeMinIdle
			redisClient.SubscribeRedis.MinIdleConns = changeMinIdle
		}

		changeMaxIdle = viper.GetInt("subscribe.max_idle_conns")
		if changeMaxIdle != redisClient.SubscribeRedis.MaxIdleConns {
			subscribe_redis.Options().MaxIdleConns = changeMaxIdle
			redisClient.SubscribeRedis.MaxIdleConns = changeMaxIdle
		}

		changePoolSize = viper.GetInt("subscribe.pool_size")
		if changePoolSize != redisClient.SubscribeRedis.PoolSize {
			subscribe_redis.Options().PoolSize = changePoolSize
			redisClient.SubscribeRedis.PoolSize = changePoolSize
		}
	})
}

func CloseRedisClient() {
	if game_redis != nil {
		game_redis.Close()
	}

	if center_redis != nil {
		center_redis.Close()
	}

	if login_redis != nil {
		login_redis.Close()
	}

	if subscribe_redis != nil {
		subscribe_redis.Close()
	}
}
